/* 
 * Copyright (c) 2009, Giora Kosoi giorak@gmail.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the project nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Giora Kosoi ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Giora Kosoi BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <sparrow/util.h>
#include <sparrow/errors.h>

void parse_words(const std::string &config, WordVector &words)
{
    std::stringstream s(config);
    std::string word;
    while(s>>word)
    {
        words.insert(words.end(), word);
    }
}

timespec totimespec(uint32_t milliseconds)
{
    timespec t;
    t.tv_sec = milliseconds / 1000;
    t.tv_nsec = (milliseconds % 1000) * 1000000;
    return t;
}

timespec totimespec(time_t sec, long int nsec)
{
    timespec t;
    t.tv_sec = sec;
    t.tv_nsec = nsec;
    return t;
}

const Octets &join(Octets &result, const char *sep, ...)
{
    result = Octets();
    va_list ap;
    va_start(ap, sep);
    const char *elem = va_arg(ap, const char *);
    while(elem != NULL)
    {
        result.insert(result.end(), elem, elem + strlen(elem));
        elem = va_arg(ap, const char *);
        if(elem != NULL)
        {
            result.insert(result.end(), sep, sep + strlen(sep));
        }
    }
    va_end(ap);
    return result;
}

const std::vector<Octets> &split(std::vector<Octets> &result, const Octets &input, const char *sep)
{
    typedef  std::vector<Octets> _result_type;
    result = _result_type();
    const char *sep_begin = sep;
    const char *sep_end = sep_begin + strlen(sep);
    Octets::const_iterator end = input.end();
    Octets::const_iterator element_begin = input.begin();
    Octets::const_iterator element_end = std::search(element_begin, end, sep_begin, sep_end);

    while(element_end < end)
    {
        result.push_back(Octets(element_begin, element_end));
        element_begin = element_end + (sep_end - sep_begin);
        element_end = std::search(element_begin, end, sep_begin, sep_end);
    }
    result.push_back(Octets(element_begin, element_end));
    return result;
}

const Octets &make_octets(Octets &result, const std::string &s)
{
    result.assign(s.begin(), s.end());
    return result;
}

Octets make_octets(const std::string &s)
{
    return  Octets(s.begin(), s.end());
}

std::string head(const Octets &buff, size_t len)
{
    return std::string(buff.begin(), buff.begin() + std::min(len, buff.size()));
}

std::string tail(const Octets &buff, size_t len)
{
    return std::string(buff.end() - std::min(len, buff.size()), buff.end());
}

std::string head_dots_tail(const Octets &buff, size_t len)
{
    // shorten string for printing "head ... tail"
}

std::string head(const Slice &buff, size_t len)
{
    return std::string(buff.begin(), buff.begin() + std::min(len, buff.size()));
}

std::string tail(const Slice &buff, size_t len)
{
    return std::string(buff.end() - std::min(len, buff.size()), buff.end());
}

std::string head_dots_tail(const Slice &buff, size_t len)
{

}

bool equal_no_case(const std::string &s1, const std::string &s2)
{
    if(s1.size() != s2.size())
    {
        return false;
    }
    
    std::string::const_iterator i1 = s1.begin();
    std::string::const_iterator end1 = s1.end();

    std::string::const_iterator i2 = s2.begin();

    while(i1 != end1)
    {
        if(tolower(*i1) != tolower(*i2))
        {
            return false;
        }
        ++i1;
        ++i2;
    }
    return true;
}

void gethostbyname(const std::string &name, sockaddr_in &addr)
{
    struct hostent hostbuff;
    struct hostent *hp;
    size_t host_buff_len;
    char *tmp_host_buff;
    int result;
    int herr;

    host_buff_len = 1024;
    tmp_host_buff = (char *)malloc(host_buff_len);
    while((result = 
                gethostbyname_r(
                    name.c_str(), 
                    &hostbuff, 
                    tmp_host_buff, 
                    host_buff_len, 
                    &hp, 
                    &herr)) == ERANGE)
    {
        host_buff_len *= 2;
        tmp_host_buff = (char *)realloc(tmp_host_buff, host_buff_len);
    }
    if(result || hp == NULL)
    {
        printf("%s\n", strerror(errno));
        free(tmp_host_buff);
        throw_error<std::runtime_error>(__FILE__, __LINE__,
                "failed gethostbyname for [%s]", name.c_str());
    }
    memcpy(&addr.sin_addr.s_addr, hp->h_addr, sizeof(addr.sin_addr.s_addr));
    free(tmp_host_buff);
}

